home *** CD-ROM | disk | FTP | other *** search
- /*
- * picasm.c
- *
- * Freely distributable for non-commercial use (basically,
- * don't sell this program without my permission. You can
- * use it for developing commercial PIC applications, but
- * of course I am not responsible for any damages caused by
- * this assembler generating bad code or anything like that)
- *
- * Copyright 1995-1998 by Timo Rossi
- * See the file picasm.doc for more information
- *
- * email: trossi@iki.fi
- * www: http://www.iki.fi/trossi/pic/
- *
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
- #include <ctype.h>
- #include <time.h>
-
- #include "picasm.h"
-
- int warnlevel;
-
- static int total_line_count;
- static int errors, warnings; /* error & warning counts */
-
- unsigned short list_flags;
-
- /* imported from devices.c */
- extern struct pic_type pic_types[];
-
- static FILE *list_fp;
- static int listing_on;
- static int list_loc;
- static pic_instr_t *list_ptr;
- static long list_val, list_len;
-
- int cond_nest_count;
- int unique_id_count;
-
- /* the current source file/macro */
- struct inc_file *current_file;
-
- /* Line buffer & pointer to it */
- char *line_buf_ptr;
- char line_buffer[256];
-
- static struct patch *global_patch_list;
- struct patch **local_patch_list_ptr;
-
- struct pic_type *pic_type;
-
- int prog_mem_size;
-
- static int reg_file_limit;
-
- short code_generated;
-
- static pic_instr_t prog_mem[PROGMEM_MAX];
- static pic_instr_t data_eeprom[EEPROM_MAX];
- static pic_instr_t pic_id[4];
- pic_instr_t config_fuses;
-
- org_mode_t O_Mode;
-
- int prog_location; /* current address for program code */
- int reg_location; /* current address for register file */
- int edata_location; /* current address for data EEPROM */
- int org_val;
-
- int local_level;
-
- /* Error handling */
- /*
- * Show line number/line with error message
- */
- static void
- err_line_ref(void)
- {
- struct inc_file *inc;
-
- if(current_file != NULL) {
- inc = current_file;
- if(inc->type != INC_FILE) {
- fprintf(stderr, "(Macro %s line %d) ",
- inc->v.m.sym->name, inc->linenum);
- while(inc != NULL && inc->type != INC_FILE)
- inc = inc->next;
- }
- fprintf(stderr, "File '%s' at line %d:\n",
- inc->v.f.fname, inc->linenum);
- fputs(line_buffer, stderr);
- if(line_buffer[0] != '\0' && line_buffer[strlen(line_buffer)-1] != '\n')
- fputc('\n', stderr);
- }
- }
-
- /*
- * Warning message
- */
- void
- warning(char *fmt, ...)
- {
- va_list args;
-
- err_line_ref();
- fputs("Warning: ", stderr);
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- if(list_fp != NULL) {
- fputs("Warning: ", list_fp);
- vfprintf(list_fp, fmt, args);
- fputc('\n', list_fp);
- }
- fputc('\n', stderr);
- va_end(args);
- warnings++;
- }
-
- /*
- * skip the end of line, in case of an error
- */
- static void
- error_lineskip(void)
- {
- write_listing_line(0);
- skip_eol();
- get_token();
- }
-
- /*
- * Error message
- * call error_lineskip() if lskip is non-zero
- *
- */
- void
- error(int lskip, char *fmt, ...)
- {
- va_list args;
-
- err_line_ref();
- fputs("Error: ", stderr);
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- if(list_fp != NULL) {
- fputs("Error: ", list_fp);
- vfprintf(list_fp, fmt, args);
- fputc('\n', list_fp);
- }
- fputc('\n', stderr);
- va_end(args);
- if(++errors >= MAX_ERRORS)
- fatal_error("too many errors, aborting");
-
- if(lskip)
- error_lineskip();
- }
-
- /*
- * Fatal error message
- */
- void
- fatal_error(char *fmt, ...)
- {
- va_list args;
-
- err_line_ref();
- fputs("Fatal error: ", stderr);
- va_start(args, fmt);
- vfprintf(stderr, fmt, args);
- fputc('\n', stderr);
- va_end(args);
- exit(EXIT_FAILURE);
- }
-
- /* memory allocation */
- void *
- mem_alloc(int size)
- {
- void *p;
-
- if((p = malloc(size)) == NULL)
- fatal_error("Out of memory");
-
- return p;
- }
-
- /*
- * initialize the assembler
- */
- static void
- init_assembler(void)
- {
- pic_instr_t *cp;
- int n;
-
- init_symtab(); /* initialize symbol table */
-
- /* initialize program memory to invalid values */
- for(n = PROGMEM_MAX, cp = prog_mem; n-- > 0; *cp++ = INVALID_INSTR);
-
- /* initialize data memory to invalid values */
- for(n = EEPROM_MAX, cp = data_eeprom; n-- > 0; *cp++ = INVALID_DATA);
-
- /* initialize jump patch list */
- global_patch_list = NULL;
-
- prog_location = -1;
- reg_location = -1;
- edata_location = -1;
-
- org_val = -1;
-
- current_file = NULL;
-
- config_fuses = INVALID_CONFIG;
- pic_id[0] = INVALID_ID;
-
- errors = warnings = 0;
-
- list_flags = 0;
- list_len = 0;
- listing_on = 1;
-
- cond_nest_count = 0;
- unique_id_count = 1;
- total_line_count = 0;
- code_generated = 0;
-
- local_level = 0;
-
- ifskip_mode = 0;
- }
-
- /*
- * generate program code
- */
- void gen_code(int val)
- {
- if(pic_type == NULL)
- fatal_error("PIC device type not set");
-
- if(O_Mode == O_NONE) {
- O_Mode = O_PROGRAM;
-
- if(org_val < 0) {
- error(0, "ORG value not set");
- prog_location = 0;
- return;
- }
-
- prog_location = org_val;
- } else if(O_Mode != O_PROGRAM) {
- error(0, "ORG mode conflict");
- O_Mode = O_PROGRAM;
- return;
- }
-
- if(prog_location >= prog_mem_size)
- fatal_error("Code address out of range");
-
- if(prog_mem[prog_location] != INVALID_INSTR)
- warning("Overlapping code at 0x%x\n", prog_location);
-
- if((list_flags & LIST_PROG) == 0) {
- list_loc = prog_location;
- list_flags = LIST_LOC | LIST_PROG;
- }
- list_len++;
-
- prog_mem[prog_location++] = val;
-
- code_generated = 1;
- }
-
- /*
- * Generate data for data EEPROM
- */
- void
- gen_edata(int val)
- {
- if(O_Mode == O_NONE) {
- O_Mode = O_EDATA;
-
- if(org_val < 0) {
- error(0, "ORG value not set");
- edata_location = 0;
- return;
- }
-
- edata_location = org_val;
- } else if(O_Mode != O_EDATA) {
- error(0, "ORG mode conflict");
- O_Mode = O_EDATA;
- return;
- }
-
- if(edata_location >= pic_type->eeprom_size)
- fatal_error("Data EEPROM address out of range");
-
- if(data_eeprom[edata_location] < 0x100)
- warning("Overlapping EEPROM data at 0x%x\n", edata_location);
-
- if((list_flags & LIST_LOC) == 0) {
- list_loc = edata_location;
- list_flags = LIST_LOC | LIST_EDATA;
- }
- list_len++;
-
- data_eeprom[edata_location++] = val;
-
- code_generated = 1;
- }
-
- /*
- * Write one line of Intel-hex file
- */
- static void
- write_hex_record(FILE *fp,
- int reclen, /* length (in words) */
- int loc, /* address */
- pic_instr_t *data, /* pointer to word data */
- int format) /* IHX8M or IHX16 */
- {
- int check = 0;
-
- switch(format) {
- case IHX8M:
- fprintf(fp, ":%02X%04X00", 2*reclen, 2*loc);
- check += ((2*loc) & 0xff) + (((2*loc) >> 8) & 0xff) + 2*reclen;
- break;
-
- case IHX16:
- fprintf(fp, ":%02X%04X00", reclen, loc);
- check += (loc & 0xff) + ((loc >> 8) & 0xff) + reclen;
- break;
- }
-
- while(reclen--) {
- switch(format) {
- case IHX8M:
- fprintf(fp, "%02X%02X",
- (int)(*data & 0xff), (int)((*data >> 8) & 0xff));
- break;
-
- case IHX16:
- fprintf(fp, "%02X%02X",
- (int)((*data >> 8) & 0xff), (int)(*data & 0xff));
- break;
- }
- check += (*data & 0xff) + ((*data >> 8) & 0xff);
- data++;
- }
-
- /* write checksum, assumes 2-complement */
- fprintf(fp, "%02X" HEX_EOL, (-check) & 0xff);
- }
-
- /*
- * Write output file in ihx8m or ihx16-format
- *
- */
- static void
- write_output(char *fname, int format)
- {
- int loc, reclen;
- FILE *fp;
-
- if((fp = fopen(fname, "w")) == NULL)
- fatal_error("Can't create file '%s'", fname);
-
- /* program */
- for(loc = 0;;) {
- while(loc < prog_mem_size && prog_mem[loc] == INVALID_INSTR)
- loc++;
-
- if(loc >= prog_mem_size)
- break;
-
- reclen = 0;
- while(reclen < 8 && loc < prog_mem_size
- && prog_mem[loc] != INVALID_INSTR) {
- loc++;
- reclen++;
- }
- write_hex_record(fp, reclen, loc-reclen, &prog_mem[loc-reclen], format);
- }
-
- /* PIC ID */
- if(pic_id[0] != INVALID_ID) {
- switch(pic_type->instr_set) {
- case PIC12BIT:
- write_hex_record(fp, 4, prog_mem_size, pic_id, format);
- break;
-
- case PIC14BIT:
- write_hex_record(fp, 4, 0x2000, pic_id, format);
- break;
- }
- }
-
- /* config fuses */
- if(config_fuses != INVALID_CONFIG) {
- write_hex_record(fp, 1, pic_type->fuse_addr, &config_fuses, format);
- }
-
- if(pic_type->eeprom_size > 0) { /* data EEPROM */
- for(loc = 0;;) {
- while(loc < pic_type->eeprom_size && data_eeprom[loc] >= 0x100)
- loc++;
-
- if(loc >= pic_type->eeprom_size)
- break;
-
- reclen = 0;
- while(reclen < 8 && loc < pic_type->eeprom_size
- && data_eeprom[loc] < 0x100) {
- loc++;
- reclen++;
- }
- write_hex_record(fp, reclen, 0x2100+loc-reclen,
- &data_eeprom[loc-reclen], format);
- }
- }
-
- fputs(":00000001FF" HEX_EOL , fp); /* end record */
- fclose(fp);
- }
-
- /*
- * Write one line to listing file (if listing is enabled)
- */
- void
- write_listing_line(int cond_flag)
- {
- int i;
-
- if(list_fp != NULL && listing_on) {
- fprintf(list_fp, "%04d%c%c",
- ++total_line_count,
- (current_file != NULL && current_file->type == INC_MACRO ?
- '+' : ' '),
- (cond_flag ? '!' : ' '));
-
- if(line_buffer[0] != '\0') {
- if(list_flags & LIST_VAL) {
- fprintf(list_fp, "%08lX ", list_val);
- } else {
- if(list_flags & LIST_LOC)
- fprintf(list_fp, "%04X", list_loc);
- else
- fputs(" ", list_fp);
-
- if((list_flags & (LIST_PROG|LIST_EDATA|LIST_PTR)) != 0) {
- fputc(((list_flags & LIST_FORWARD) ? '?' : ' '), list_fp);
- if(list_flags & LIST_PROG) {
- fprintf(list_fp, "%04X ", prog_mem[list_loc]);
- } else if(list_flags & LIST_EDATA) {
- fprintf(list_fp, "%04X ", data_eeprom[list_loc]);
- } else if(list_flags & LIST_PTR) {
- fprintf(list_fp, "%04X ", *list_ptr++);
- }
- } else {
- fputs(" ", list_fp);
- }
- }
-
- fputs(line_buffer, list_fp);
- if(line_buffer[0] != '\0'
- && line_buffer[strlen(line_buffer)-1] != '\n')
- fputc('\n', list_fp);
-
- list_len--;
- for(i = 0; i < list_len; i++) {
- list_loc++;
- fprintf(list_fp, "%04d%c ",
- total_line_count,
- (current_file != NULL
- && current_file->type == INC_MACRO ?
- '+' : ' '));
-
- if(list_flags & LIST_LOC)
- fprintf(list_fp, "%04X", list_loc);
- else
- fputs(" ", list_fp);
-
- if(list_flags & LIST_PROG) {
- fprintf(list_fp, " %04X\n", prog_mem[list_loc]);
- } else if(list_flags & LIST_EDATA) {
- fprintf(list_fp, " %04X\n", data_eeprom[list_loc]);
- } else if(list_flags & LIST_PTR) {
- fprintf(list_fp, " %04X\n", *list_ptr++);
- }
- }
- }
-
- if(listing_on < 0)
- listing_on = 0;
- }
- list_flags = 0;
- list_len = 0;
- }
-
- /*
- * parse and handle OPT-directive
- * (this is special as it must be done as macro definition time
- * if inside a macro)
- */
- static int
- handle_opt(void)
- {
- if(token_type != TOK_IDENTIFIER) {
- error(1, "OPT syntax error");
- return FAIL;
- }
- /*
- * Note: when listing is turned off, 'listing_on' is set to -1
- * here and the listing routine sets it to zero after listing
- * the line containing the 'opt nol'.
- */
- if(strcasecmp(token_string, "nol") == 0
- || strcasecmp(token_string, "nolist") == 0) {
- listing_on = -1;
- } else if(strcasecmp(token_string, "l") == 0
- || strcasecmp(token_string, "list") == 0) {
- listing_on = 1;
- } else {
- error(1, "OPT syntax error");
- return FAIL;
- }
-
- get_token();
- return OK;
- }
-
- /*
- * Define a macro
- */
- static void
- define_macro(char *name)
- {
- struct symbol *sym;
- struct macro_line *ml;
- int t;
-
- if(token_type != TOK_NEWLINE && token_type != TOK_EOF)
- error(0, "Extraneous characters after a valid source line");
- skip_eol();
-
- write_listing_line(0);
-
- sym = add_symbol(name, SYMTAB_GLOBAL);
- sym->type = SYM_MACRO;
- sym->v.text = NULL;
- ml = NULL;
-
- for(;;) {
- get_token(); /* read first token on next line */
- t = 0;
- if(token_type == TOK_IDENTIFIER) {
- t = 1;
- get_token();
- if(token_type == TOK_COLON)
- get_token();
- }
- if(token_type == TOK_EOF || token_type == KW_END)
- fatal_error("Macro definition not terminated");
-
- if(token_type == KW_MACRO)
- fatal_error("Nested macro definitions not allowed");
-
- if(token_type == KW_ENDM) /* end macro definition */
- break;
-
- /* OPT must be handled inside macros at definition time */
- if(token_type == KW_OPT) {
- get_token();
- handle_opt();
- } else {
- if(ml == NULL) {
- ml = mem_alloc(sizeof(struct macro_line)
- +strlen(line_buffer));
- sym->v.text = ml;
- } else {
- ml->next = mem_alloc(sizeof(struct macro_line)
- +strlen(line_buffer));
- ml = ml->next;
- }
- strcpy(ml->text, line_buffer);
- ml->next = NULL;
- }
-
- write_listing_line(0);
-
- line_buf_ptr = NULL;
- tok_char = ' ';
- }
- if(t)
- error(0, "Label not allowed with ENDM");
- get_token();
- }
-
- /*
- * Skip subroutine used by the conditional assembly directives
- * return: -1=premature EOF, 0=ok, 1=label (not allowed)
- */
- static int
- if_else_skip(void)
- {
- int t, ccount;
-
- ccount = 0;
- ifskip_mode++;
- do {
- skip_eol();
- get_token();
- write_listing_line(1);
-
- t = 0;
- if(token_type == TOK_IDENTIFIER) {
- t = 1;
- get_token();
- if(token_type == TOK_COLON)
- get_token();
- }
- if(token_type == KW_IF) {
- ccount++;
- } else if(token_type == KW_ENDIF) {
- if(ccount <= 0)
- break;
- ccount--;
- } else if(token_type == KW_ELSE && ccount <= 0) {
- break;
- }
- } while(token_type != TOK_EOF && token_type != KW_END);
-
- ifskip_mode--;
- return (token_type == TOK_EOF || token_type == KW_END) ? -1 : t;
- }
-
- /*
- * Add a patch pointing to the current location
- */
- void
- add_patch(int tab, struct symbol *sym, patchtype_t type)
- {
- struct patch **patch_list_ptr, *ptch;
-
- patch_list_ptr =
- (tab == SYMTAB_GLOBAL ? &global_patch_list : local_patch_list_ptr);
-
- if(O_Mode == O_NONE) {
- O_Mode = O_PROGRAM;
- if(org_val < 0) {
- error(0, "ORG value not set");
- prog_location = 0;
- return;
- }
- prog_location = org_val;
- }
-
- ptch = mem_alloc(sizeof(struct patch));
- ptch->label = sym;
- ptch->type = type;
- ptch->location = prog_location;
-
- /* add a new patch to patch_list */
- ptch->next = *patch_list_ptr;
- *patch_list_ptr = ptch;
- }
-
- /*
- * Apply the store patches and also free the patch list
- */
- static void
- apply_patches(struct patch *patch_list)
- {
- struct patch *ptch, *p2;
-
- /*
- * fix forward jumps/calls
- */
- for(ptch = patch_list; ptch != NULL; ptch = p2) {
- p2 = ptch->next;
-
- if(ptch->label->type == SYM_FORWARD)
- error(0, "Undefined label '%s%s'",
- (patch_list == global_patch_list ? "" : "="),
- ptch->label->name);
- else
- switch(ptch->type) {
- case PATCH8:
- if(pic_type->instr_set == PIC12BIT && (ptch->label->v.value & 0x100) != 0
- && (prog_mem[ptch->location] & 0xff00) == 0x900)
- error(0, "CALL address in upper half of a page (label '%s%s')",
- (patch_list == global_patch_list ? "" : "="),
- ptch->label->name);
-
- prog_mem[ptch->location] =
- (prog_mem[ptch->location] & 0xff00)
- | (ptch->label->v.value & 0xff);
- break;
-
- case PATCH9:
- prog_mem[ptch->location] =
- (prog_mem[ptch->location] & 0xfe00)
- | (ptch->label->v.value & 0x1ff);
- break;
-
- case PATCH11:
- prog_mem[ptch->location] =
- (prog_mem[ptch->location] & 0xf800)
- | (ptch->label->v.value & 0x7ff);
- break;
- }
- mem_free(ptch);
- }
- }
-
- /*
- * Generate code for an instruction with 8-bit literal data
- * allows forward references
- */
- int
- gen_byte_c(int instr_code)
- {
- int t, symtype;
- long val;
- struct symbol *sym;
-
- t = 0;
- if(token_type == TOK_IDENTIFIER || token_type == TOK_LOCAL_ID) {
- symtype =
- (token_type == TOK_IDENTIFIER ? SYMTAB_GLOBAL : SYMTAB_LOCAL);
-
- if(symtype == SYMTAB_LOCAL && local_level == 0) {
- error(1, "Local symbol outside a LOCAL block");
- return FAIL;
- }
-
- sym = lookup_symbol(token_string, symtype);
- if(sym == NULL || sym->type == SYM_FORWARD) {
- if(sym == NULL) {
- sym = add_symbol(token_string, symtype);
- sym->type = SYM_FORWARD;
- }
-
- add_patch(symtype, sym, PATCH8);
- get_token();
- gen_code(instr_code);
- list_flags |= LIST_FORWARD;
- return OK;
- }
- }
-
- val = get_expression();
- if(expr_error)
- return FAIL;
-
- if(val < -0x80 || val > 0xff) {
- error(0, "8-bit literal out of range");
- return FAIL;
- }
-
- gen_code(instr_code | (val & 0xff));
- return OK;
- }
-
- /*
- * check if the current token is a valid ORG mode specifier
- * and return the mode (or O_NONE if not valid mode specifier)
- */
- static int
- org_mode(void)
- {
- if(token_type == KW_EDATA)
- return O_EDATA;
-
- if(token_type == TOK_IDENTIFIER) {
- if(strcasecmp(token_string, "code") == 0)
- return O_PROGRAM;
-
- if(strcasecmp(token_string, "reg") == 0)
- return O_REGFILE;
- }
-
- return O_NONE;
- }
-
- /*
- * The assembler itself
- */
- static void
- assembler(char *fname)
- {
- static char symname[256];
- struct symbol *sym;
- int op, t, symtype;
- long val;
- char *cp;
- struct pic_type *pic;
-
- if(pic_type != NULL) {
- sprintf(symname, "__%s", pic_type->name);
- sym = add_symbol(symname, SYMTAB_GLOBAL);
- sym->type = SYM_DEFINED;
- sym->v.value = 1;
- }
-
- begin_include(fname);
- get_token();
-
- while(token_type != TOK_EOF) {
- sym = NULL;
- if(token_type == TOK_IDENTIFIER || token_type == TOK_LOCAL_ID) {
- symtype =
- (token_type == TOK_IDENTIFIER ? SYMTAB_GLOBAL : SYMTAB_LOCAL);
-
- if(symtype == SYMTAB_LOCAL && local_level == 0) {
- error(1, "Local symbol outside a LOCAL block");
- continue;
- }
-
- t = (line_buf_off == 0);
-
- strcpy(symname, token_string);
- sym = lookup_symbol(symname, symtype);
- if(sym != NULL && sym->type == SYM_MACRO) {
- /* skip whitespace */
- while(tok_char != '\n' && isspace(tok_char))
- read_src_char();
-
- if(line_buf_ptr != NULL &&
- strncasecmp(line_buf_ptr-1, "macro", 5) == 0 &&
- line_buf_ptr[4] != '.' && line_buf_ptr[4] != '_' &&
- !isalnum((unsigned char)line_buf_ptr[4])) {
- error(1, "Multiple definition of macro '%s'", symname);
- continue;
- }
-
- expand_macro(sym);
- continue;
- }
-
- get_token();
- switch(token_type) {
- case KW_MACRO:
- get_token();
- if(sym != NULL) {
- error(1, "Multiply defined symbol '%s%s'",
- (symtype == SYMTAB_LOCAL ? "=" : ""),
- sym->name);
- continue;
- }
- define_macro(symname);
- goto line_end;
-
- case KW_EQU:
- if(sym != NULL) {
- if(sym->type != SYM_FORWARD)
- error(0, "Multiply defined symbol '%s%s'",
- (symtype == SYMTAB_LOCAL ? "=" : ""),
- sym->name);
- } else
- sym = add_symbol(symname, symtype);
- get_token();
- sym->type = SYM_DEFINED;
- sym->v.value = get_expression();
- if(expr_error)
- continue; /* error_lineskip() done in expr.c */
-
- list_val = sym->v.value;
- list_flags = LIST_VAL;
- goto line_end;
-
- case KW_SET:
- if(sym != NULL && sym->type != SYM_SET)
- error(0, "Multiply defined symbol '%s%s'",
- (symtype == SYMTAB_LOCAL ? "=" : ""),
- sym->name);
- else if(sym == NULL)
- sym = add_symbol(symname, symtype);
- get_token();
- sym->type = SYM_SET;
- sym->v.value = get_expression();
- if(expr_error)
- continue;
-
- list_val = sym->v.value;
- list_flags = LIST_VAL;
- goto line_end;
-
- case TOK_COLON:
- get_token();
- goto do_label;
-
- default:
- if(t == 0)
- warning("Label not in the beginning of a line");
-
- do_label:
- switch(O_Mode) {
- case O_PROGRAM:
- t = prog_location;
- break;
-
- case O_REGFILE:
- t = reg_location;
- break;
-
- case O_EDATA:
- t = edata_location;
- break;
-
- case O_NONE:
- t = org_val;
- break;
- }
-
- if(t < 0) {
- error(0, "ORG value not set");
- } else {
- if(sym != NULL && sym->type != SYM_FORWARD)
- error(0, "Multiply defined symbol '%s%s'",
- (symtype == SYMTAB_LOCAL ? "=" : ""),
- sym->name);
- if(sym == NULL)
- sym = add_symbol(symname, symtype);
- sym->type = SYM_DEFINED;
- sym->v.value = t;
- list_loc = t;
- list_flags = LIST_LOC;
- }
- break;
- }
- }
-
- /* if this line has a label, 'sym' points to it */
-
- if(token_type == TOK_NEWLINE) {
- write_listing_line(0);
- get_token();
- continue;
- }
-
- if(token_type == TOK_IDENTIFIER &&
- (sym = lookup_symbol(token_string, SYMTAB_GLOBAL))
- != NULL && sym->type == SYM_MACRO) {
- expand_macro(sym);
- continue;
- }
-
- if(token_type == KW_END)
- break;
-
- if(token_type == KW_ERROR) {
- while(isspace((unsigned char)(*line_buf_ptr)))
- line_buf_ptr++;
- error(1, "%s", line_buf_ptr);
- continue;
- }
-
- op = token_type;
- get_token();
-
- switch(op) {
- case KW_INCLUDE:
- if(token_type != TOK_STRCONST) {
- error(1, "Missing file name after INCLUDE");
- continue;
- }
-
- strcpy(symname, token_string);
- get_token();
- if(token_type != TOK_NEWLINE && token_type != TOK_EOF)
- error(0, "Extraneous characters after a valid source line");
-
- begin_include(symname);
-
- write_listing_line(0);
- get_token();
- continue;
-
- case KW_SET:
- case KW_EQU:
- if(sym == NULL)
- error(1, "SET/EQU without a label");
- else
- error(1, "SET/EQU syntax error");
- continue;
-
- case KW_MACRO:
- error(1, "MACRO without a macro name");
- continue;
-
- case KW_ENDM:
- error(1, "ENDM not allowed outside a macro");
- continue;
-
- case KW_EXITM:
- /*
- * EXITM works now (version 0.97). Strange that
- * nobody noticed that it wasn't implemented
- * at all in previous versions.
- */
- if(current_file == NULL || current_file->type != INC_MACRO) {
- error(1, "EXITM not allowed outside a macro");
- continue;
- }
- cond_nest_count = current_file->cond_nest_count;
- end_include();
- break;
-
- case KW_OPT:
- if(handle_opt() != OK) {
- error_lineskip();
- continue;
- }
- break;
-
- case KW_LOCAL:
- add_local_symtab();
- break;
-
- case KW_ENDLOCAL:
- if(local_level == 0) {
- error(1, "ENDLOCAL without LOCAL");
- continue;
- }
-
- apply_patches(*local_patch_list_ptr);
- remove_local_symtab();
- break;
-
- case KW_IF:
- if(sym != NULL)
- error(0, "Label not allowed with IF");
-
- val = get_expression();
-
- if(token_type != TOK_NEWLINE && token_type != TOK_EOF)
- error(0, "Extraneous characters after a valid source line");
-
- if(val == 0) {
- write_listing_line(0);
- t=if_else_skip();
- if(t == -1)
- fatal_error("Conditional not terminated");
- else if(t == 1)
- error(0, "Label not allowed with %s",
- (token_type == KW_ELSE ? "ELSE" : "ENDIF"));
-
- if(token_type == KW_ELSE)
- cond_nest_count++;
- get_token();
- goto line_end2;
- } else
- cond_nest_count++;
- break;
-
- case KW_ELSE:
- if(sym != NULL)
- error(0, "Label not allowed with %s", "ELSE");
-
- if(current_file == NULL
- || cond_nest_count <= current_file->cond_nest_count)
- error(0, "ELSE without IF");
-
- write_listing_line(0);
- t = if_else_skip();
- if(t == -1)
- fatal_error("Conditional not terminated");
- else if(t == 1)
- error(0, "Label not allowed with %s",
- (token_type == KW_ELSE ? "ELSE" : "ENDIF"));
-
- if(token_type == KW_ELSE)
- error(0, "Multiple ELSE statements with one IF");
-
- cond_nest_count--;
-
- get_token();
- goto line_end2;
-
- case KW_ENDIF:
- if(sym != NULL)
- error(0, "Label not allowed with %s", "ENDIF");
-
- if(current_file == NULL
- || cond_nest_count <= current_file->cond_nest_count)
- error(0, "ENDIF without IF");
-
- cond_nest_count--;
- break;
-
- case KW_ORG:
- if(pic_type == NULL)
- fatal_error("PIC device type not set");
-
- org_val = -1;
- if((t = org_mode()) != O_NONE) {
- get_token();
- O_Mode = (org_mode_t)t;
- switch(O_Mode) {
- case O_PROGRAM:
- case O_NONE: /* shut up GCC warning, cannot really happen here */
- org_val = prog_location;
- break;
-
- case O_REGFILE:
- org_val = reg_location;
- break;
-
- case O_EDATA:
- org_val = edata_location;
- break;
- }
- if(org_val < 0) {
- error(0, "ORG value not set");
- O_Mode = O_NONE;
- }
- break;
- }
-
- val = get_expression();
- if(expr_error)
- continue;
-
- if(val < 0 || val >= prog_mem_size) {
- error(1, "ORG value out of range");
- continue;
- }
-
- org_val = val;
- O_Mode = O_NONE;
-
- if(token_type == TOK_COMMA) {
- get_token();
- if((t = org_mode()) == O_NONE) {
- error(0, "Invalid ORG mode");
- } else {
- O_Mode = (org_mode_t)t;
- switch(O_Mode)
- {
- case O_PROGRAM:
- case O_NONE: /* shut up GCC warning, cannot really happen here */
- prog_location = org_val;
- break;
-
- case O_REGFILE:
- reg_location = org_val;
- break;
-
- case O_EDATA:
- edata_location = org_val;
- break;
- }
- }
-
- get_token();
- }
-
- list_loc = org_val;
- list_flags = LIST_LOC;
- break;
-
- case KW_DS:
- val = get_expression();
- if(expr_error)
- continue;
-
- if(O_Mode == O_NONE) {
- O_Mode = O_REGFILE;
- if(org_val < 0) {
- error(0, "ORG value not set");
- reg_location = 0;
- } else
- reg_location = org_val;
- }
-
- if(O_Mode != O_REGFILE)
- error(0, "ORG mode conflict");
- else {
- if(reg_location >= reg_file_limit)
- fatal_error("Register file address out of range");
- list_loc = reg_location;
- list_flags = LIST_LOC;
- reg_location += val;
- }
- break;
-
- case KW_EDATA:
- if(pic_type == NULL)
- fatal_error("PIC device type not set");
-
- if(pic_type->eeprom_size == 0) {
- error(1, "PIC%s does not have data EEPROM", pic_type->name);
- continue;
- }
-
- for(;;) {
- if(token_type == TOK_STRCONST) {
- for(cp = token_string; *cp != '\0'; cp++)
- gen_edata((int)((unsigned char)(*cp)));
- get_token();
- } else {
- val = get_expression();
- if(expr_error)
- break;
-
- if(val < 0 || val > 0xff) {
- error(0, "Data EEPROM byte out of range");
- } else
- gen_edata(val);
- }
- if(token_type != TOK_COMMA)
- break;
-
- get_token();
- }
- break;
-
- case KW_CONFIG:
- if(pic_type == NULL)
- fatal_error("PIC device type not set");
-
- if(config_fuses != INVALID_CONFIG) {
- error(1, "Multiple CONFIG definitions");
- continue;
- }
-
- parse_config();
-
- list_flags = LIST_PTR;
- list_ptr = &config_fuses;
- list_len = 1;
- break;
-
- /* Device type */
- case KW_DEVICE:
- if(token_type != TOK_IDENTIFIER && token_type != TOK_STRCONST) {
- error(1, "DEVICE requires a device type");
- continue;
- }
-
- cp = token_string;
- if(strncasecmp(token_string, "PIC", 3) == 0)
- cp += 3;
-
- for(pic = pic_types; pic->name != NULL; pic++) {
- if(strcasecmp(pic->name, cp) == 0)
- break;
- }
- if(pic->name == NULL)
- fatal_error("Invalid PIC device type");
-
- get_token();
- if(pic_type == pic)
- break;
-
- if(pic_type != NULL) {
- error(1, "Duplicate DEVICE setting");
- continue;
- }
- pic_type = pic;
- prog_mem_size = pic_type->progmem_size;
- reg_file_limit = pic_type->regfile_limit;
-
- sprintf(symname, "__%s", pic_type->name);
- sym = add_symbol(symname, SYMTAB_GLOBAL);
- sym->type = SYM_DEFINED;
- sym->v.value = 1;
- break;
-
- /* PIC ID */
- case KW_PICID:
- if(pic_type == NULL)
- fatal_error("PIC device type not set");
-
- if(pic_id[0] != INVALID_ID) {
- error(1, "Multiple ID definitions");
- continue;
- }
-
- /*
- * should check if ID is really allowed for all PIC types.
- * Microchip 1994 databook specfically says that ID is not
- * implemented on PIC16C6x/74... but 1995/96 databook
- * has different information about that...
- */
-
- for(t = 0;;) {
- val = get_expression();
- if(expr_error)
- continue;
-
- if(val < 0 || val > 0x3fff)
- error(0, "PIC ID value out of range");
- else {
- if(t >= 4) {
- error(1, "PIC ID too long (max 4 bytes)");
- continue;
- }
- pic_id[t] = (pic_instr_t)val;
- }
-
- t++;
-
- if(token_type != TOK_COMMA)
- break;
-
- get_token();
- }
-
- if(t > 0) {
- list_flags = LIST_PTR;
- list_len = t;
- list_ptr = pic_id;
-
- while(t < 4)
- pic_id[t++] = 0x3fff;
- }
- break;
-
- /* mnemonics */
-
- default:
- switch(pic_type->instr_set) {
- case PIC12BIT:
- t = assemble_12bit_mnemonic(op);
- break;
-
- case PIC14BIT:
- default:
- t = assemble_14bit_mnemonic(op);
- break;
- }
- if(t != OK)
- continue;
- break;
- }
-
- line_end:
- write_listing_line(0);
-
- line_end2:
- if(token_type == TOK_EOF)
- continue;
-
- if(token_type != TOK_NEWLINE) {
- error(0, "Extraneous characters after a valid source line");
- skip_eol();
- }
- get_token();
- } /* while(token_type != TOK_EOF) */
-
- /*
- * Close all open source files
- * (only really necessary if END has been used)
- */
- while(current_file != NULL)
- end_include();
-
- if(local_level > 0)
- error(0, "LOCAL not terminated with ENDLOCAL");
-
- apply_patches(global_patch_list);
- }
-
- /*
- * main program
- */
- int
- main(int argc, char *argv[])
- {
- static char in_filename[256], out_filename[256], list_filename[256];
- static int out_format = IHX8M;
- static int listing = 0, symdump = 0;
- char *p;
- time_t ti;
- struct tm *tm;
-
- pic_type = NULL;
- out_filename[0] = '\0';
- list_filename[0] = '\0';
- warnlevel = 0;
-
- while(argc > 1 && argv[1][0] == '-') {
- switch(argv[1][1]) {
- case 'o': /* output file name */
- if(argv[1][2] != '\0')
- strcpy(out_filename, &argv[1][2]);
- else {
- if(argc < 3) {
- fputs("-o option requires a file name\n", stderr);
- exit(EXIT_FAILURE);
- }
- strcpy(out_filename, argv[2]);
- argc--;
- argv++;
- }
- break;
-
- case 'i': case 'I': /* output hex format (ihx8m/ihx16) */
- if(strcasecmp(&argv[1][1], "ihx8m") == 0)
- out_format = IHX8M;
- else if(strcasecmp(&argv[1][1], "ihx16") == 0)
- out_format = IHX16;
- else
- goto usage;
- break;
-
- case 'p': case 'P': /* PIC type */
- if(!((argv[1][2] == 'i' || argv[1][2] == 'I') &&
- (argv[1][3] == 'c' || argv[1][3] == 'C')))
- goto usage;
-
- for(pic_type = pic_types; pic_type->name != NULL; pic_type++) {
- if(strcasecmp(pic_type->name, &argv[1][4]) == 0)
- break;
- }
-
- if(pic_type->name == NULL) {
- fprintf(stderr, "Invalid device type '%s'\n", &argv[1][1]);
- exit(EXIT_FAILURE);
- }
-
- prog_mem_size = pic_type->progmem_size;
- reg_file_limit = pic_type->regfile_limit;
- break;
-
- case 'l': /* listing/list filename */
- listing = 1;
- if(argv[1][2] != '\0')
- strcpy(list_filename, &argv[1][2]);
- break;
-
- case 's':
- symdump = 1;
- break;
-
- case 'w': /* warning mode (gives some more warnings) */
- if(argv[1][2] != '\0') {
- warnlevel = atoi(&argv[1][2]);
- } else {
- warnlevel = 1;
- }
- break;
-
- case 'v': /* version info */
- fprintf(stderr,
- "12/14-bit PIC assembler " VERSION
- " -- Copyright 1995-1998 by Timo Rossi\n"
- "AmigaOS version beta2 by RDC <rdc@cch.pmc.ru>\n");
- break;
-
- case '-': /* end of option list */
- case '\0':
- argc--;
- argv++;
- goto opt_done;
-
- default:
- goto usage;
- }
- argc--;
- argv++;
- }
-
- opt_done:
- if(argc != 2) {
- usage:
- fputs("Usage: picasm [-o<objname>] [-l<listfile>] [-s] [-ihx8m/ihx16]\n"
- " [-pic<device>] [-w[n]] [-version] <filename>\n", stderr);
- exit(EXIT_FAILURE);
- }
-
- strncpy(in_filename, argv[1], sizeof(in_filename)-1);
- if(strchr(in_filename, '.') == NULL)
- strcat(in_filename, ".asm");
-
- if(out_filename[0] == '\0') {
- strcpy(out_filename, in_filename);
- if((p = strrchr(out_filename, '.')) != NULL)
- *p = '\0';
- }
- if(strchr(out_filename, '.') == NULL)
- strcat(out_filename, ".hex");
-
- init_assembler();
-
- list_fp = NULL;
- if(listing) {
- if(list_filename[0] == '\0') {
- strcpy(list_filename, in_filename);
- if((p = strrchr(list_filename, '.')) != NULL)
- *p = '\0';
- strcat(list_filename, ".lst");
- }
-
- if((list_fp = fopen(list_filename, "w")) == NULL)
- fatal_error("Can't create listing file '%s'", list_filename);
-
- ti = time(NULL);
- tm = localtime(&ti);
-
- fprintf(list_fp, "** 12/14-bit PIC assembler " VERSION "\n");
- fprintf(list_fp, "** %s assembled %s\n",
- in_filename, asctime(tm));
- }
-
- assembler(in_filename);
- if(errors == 0) {
- if(code_generated)
- write_output(out_filename, out_format);
- else
- fputs("No code generated\n", stderr);
- }
- else
- fprintf(stderr, "%d error%s found\n", errors, errors == 1 ? "" : "s");
-
- if(warnings != 0)
- fprintf(stderr, "%d warning%s\n", warnings, warnings == 1 ? "" : "s");
-
- if(list_fp)
- {
- if(symdump)
- dump_symtab(list_fp);
- fclose(list_fp);
- }
- return EXIT_SUCCESS;
- }
-